﻿using System;
using System.Configuration;
using System.Diagnostics;
using System.Globalization;
using System.Security.Principal;
using System.Web.Mvc;
using System.Web.Security;
using Dimebrain.TweetSharp.Extensions;
using Dimebrain.TweetSharp.Fluent;
using Dimebrain.TweetSharp.Model;
using KickStart.Data;
using KickStart.Helpers;
using KickStart.Services;

//using User=KickStart.Models.User;

namespace KickStart.Controllers
{
    [HandleError]
    public class AccountController : Controller
    {

        // This constructor is used by the MVC framework to instantiate the controller using
        // the default forms authentication and membership providers.

        public AccountController()
            : this(null, null)
        {
        }

        // This constructor is not used by the MVC framework but is instead provided for ease
        // of unit testing this type. See the comments at the end of this file for more
        // information.
        public AccountController(IFormsAuthentication formsAuth, IMembershipService service)
        {
            FormsAuth = formsAuth ?? new FormsAuthenticationService();
            MembershipService = service ?? new AccountMembershipService();
        }

        public IFormsAuthentication FormsAuth
        {
            get;
            private set;
        }

        public IMembershipService MembershipService
        {
            get;
            private set;
        }

        private string _consumerKey;
        private string _consumerSecret;

        public ActionResult SignIn(string returnUrl)
        {
            _consumerKey = ConfigurationManager.AppSettings["consumerKey"];
            _consumerSecret = ConfigurationManager.AppSettings["consumerSecret"];

            var requestToken = Request["oauth_token"];
            if (requestToken == null)
            {
                MySession.ReturnUrl = returnUrl;
                //not logged in
                var request = GetRequestToken();

                // retrieve a URL used to direct the user to authorize, and 
                // return to this page with a token
                var authorizeUrl = FluentTwitter.CreateRequest()
                    .Authentication
                    .GetAuthorizationUrl(request.Token);
                if (!string.IsNullOrEmpty(returnUrl))
                {
                    authorizeUrl += "&returnUrl=" + Server.UrlEncode(returnUrl);
                }
                Response.Redirect(authorizeUrl);
            }
            else
            {
                //redirected from twitter
                returnUrl = MySession.ReturnUrl;
                // exchange returned request token for access token
                var access = GetAccessToken(requestToken);

                // make an oauth-authenticated call with the access token,
                // and remember you need to persist this token for this user's auth
                var query = FluentTwitter.CreateRequest()
                    .AuthenticateWith(_consumerKey, _consumerSecret, access.Token, access.TokenSecret)
                    .Account().VerifyCredentials().AsXml();

                // use as normal
                var response = query.Request();
                var identity = GetResponse(response);
                if (identity != null)
                {
                    MySession.LoggedInTwitterUser = identity;

                    //create user from twitter account
                    var userId = identity.Id;
                    if (UserService.GetUser(userId) == null)
                    {
                        //first login, create record
                        UserService.CreateUser(identity, access);
                    }
                    else
                    {
                        UserService.UpdateUser(identity, access);
                    }

                    //we have to update the session variable to include token info
                    MySession.CurrentUser = UserService.GetUser(userId);


                    if (String.IsNullOrEmpty(returnUrl) && string.IsNullOrEmpty(MySession.ReturnUrl))
                    {
                        FormsAuth.SignIn(userId.ToString(), true);
                        return RedirectToAction("Index", "Home");
                    }

                    if (string.IsNullOrEmpty(returnUrl))
                    {
                        returnUrl = MySession.ReturnUrl;
                        MySession.ReturnUrl = "";
                    }

                    FormsAuth.SignIn(userId.ToString(), true);

                    return Redirect(Server.UrlDecode(returnUrl));
                }
            }
            return View();
        }

        #region "Twitter Authentication"
        private TwitterUser GetResponse(string response)
        {
            var identity = response.AsUser();
            if (identity != null)
            {
                Debug.Write(String.Format("{0} authenticated successfully.", identity.ScreenName));
                return identity;
            }
            var error = response.AsError();
            if (error != null)
            {
                Debug.Write(error.ErrorMessage);
                throw new Exception(error.ErrorMessage);
            }
            return null;
        }

        private OAuthToken GetAccessToken(string requestToken)
        {
            var accessToken = FluentTwitter.CreateRequest()
                .Authentication.GetAccessToken(_consumerKey, _consumerSecret, requestToken);

            var response = accessToken.Request();
            var result = response.AsToken();

            if (result == null)
            {
                var error = response.AsError();
                if (error != null)
                {
                    throw new Exception(error.ErrorMessage);
                }
            }

            return result;
        }

        private OAuthToken GetRequestToken()
        {
            var requestToken = FluentTwitter.CreateRequest()
                .Authentication.GetRequestToken(_consumerKey, _consumerSecret);

            var response = requestToken.Request();
            var result = response.AsToken();

            if (result == null)
            {
                var error = response.AsError();
                if (error != null)
                {
                    throw new Exception(error.ErrorMessage);
                }
            }

            return result;
        }
        #endregion

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult SignIn(string username, string password, bool rememberMe, string ReturnUrl)
        {

            if (!ValidateSignIn(username, password))
            {
                var modelstates = ViewData.ModelState.ToJson();
                var result = new { success = false, errors = modelstates };
                return Json(result);


                //return View();
            }

            FormsAuth.SignIn(username, rememberMe);

            //return Json(new { success = true });

            //          if (!String.IsNullOrEmpty(ReturnUrl))
            //          {
            //              return Json(new { success = true, redirect=ReturnUrl });
            ////              return Redirect(ReturnUrl);
            //          }

            //return Json(new { success = true});
            return Json(new { success = true, redirect = "/home/index" });
            //                return RedirectToAction("Index", "Home");
        }

        public ActionResult SignOut()
        {

            FormsAuth.SignOut();

            return RedirectToAction("Index", "Home");
        }

        public ActionResult SignUp()
        {

            ViewData["PasswordLength"] = MembershipService.MinPasswordLength;

            return View();
        }

        protected override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (filterContext.HttpContext.User.Identity is WindowsIdentity)
            {
                throw new InvalidOperationException("Windows authentication is not supported.");
            }
        }

        #region Validation Methods

        private bool ValidateChangePassword(string currentPassword, string newPassword, string confirmPassword)
        {
            if (String.IsNullOrEmpty(currentPassword))
            {
                ModelState.AddModelError("currentPassword", "You must specify a current password.");
            }
            if (newPassword == null || newPassword.Length < MembershipService.MinPasswordLength)
            {
                ModelState.AddModelError("newPassword",
                                         String.Format(CultureInfo.CurrentCulture,
                                                       "You must specify a new password of {0} or more characters.",
                                                       MembershipService.MinPasswordLength));
            }

            if (!String.Equals(newPassword, confirmPassword, StringComparison.Ordinal))
            {
                ModelState.AddModelError("_FORM", "The new password and confirmation password do not match.");
            }

            return ModelState.IsValid;
        }

        private bool ValidateSignIn(string userName, string password)
        {
            if (String.IsNullOrEmpty(userName))
            {
                ModelState.AddModelError("username", "You must specify a username.");
            }
            if (String.IsNullOrEmpty(password))
            {
                ModelState.AddModelError("password", "You must specify a password.");
            }
            if (!MembershipService.ValidateUser(userName, password))
            {
                ModelState.AddModelError("_FORM", "The username or password provided is incorrect.");
            }

            return ModelState.IsValid;
        }

        private bool ValidateRegistration(string userName, string email, string password, string confirmPassword)
        {
            if (String.IsNullOrEmpty(userName))
            {
                ModelState.AddModelError("username", "You must specify a username.");
            }
            if (String.IsNullOrEmpty(email))
            {
                ModelState.AddModelError("email", "You must specify an email address.");
            }
            if (password == null || password.Length < MembershipService.MinPasswordLength)
            {
                ModelState.AddModelError("password",
                                         String.Format(CultureInfo.CurrentCulture,
                                                       "You must specify a password of {0} or more characters.",
                                                       MembershipService.MinPasswordLength));
            }
            if (!String.Equals(password, confirmPassword, StringComparison.Ordinal))
            {
                ModelState.AddModelError("_FORM", "The new password and confirmation password do not match.");
            }
            return ModelState.IsValid;
        }

        private static string ErrorCodeToString(MembershipCreateStatus createStatus)
        {
            // See http://msdn.microsoft.com/en-us/library/system.web.security.membershipcreatestatus.aspx for
            // a full list of status codes.
            switch (createStatus)
            {
                case MembershipCreateStatus.DuplicateUserName:
                    return "Username already exists. Please enter a different user name.";

                case MembershipCreateStatus.DuplicateEmail:
                    return "A username for that e-mail address already exists. Please enter a different e-mail address.";

                case MembershipCreateStatus.InvalidPassword:
                    return "The password provided is invalid. Please enter a valid password value.";

                case MembershipCreateStatus.InvalidEmail:
                    return "The e-mail address provided is invalid. Please check the value and try again.";

                case MembershipCreateStatus.InvalidAnswer:
                    return "The password retrieval answer provided is invalid. Please check the value and try again.";

                case MembershipCreateStatus.InvalidQuestion:
                    return "The password retrieval question provided is invalid. Please check the value and try again.";

                case MembershipCreateStatus.InvalidUserName:
                    return "The user name provided is invalid. Please check the value and try again.";

                case MembershipCreateStatus.ProviderError:
                    return "The authentication provider returned an error. Please verify your entry and try again. If the problem persists, please contact your system administrator.";

                case MembershipCreateStatus.UserRejected:
                    return "The user creation request has been canceled. Please verify your entry and try again. If the problem persists, please contact your system administrator.";

                default:
                    return "An unknown error occurred. Please verify your entry and try again. If the problem persists, please contact your system administrator.";
            }
        }
        #endregion
    }
}